/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package de.swta.freezay.database.controller;

import de.swta.freezay.database.controller.exceptions.IllegalOrphanException;
import de.swta.freezay.database.controller.exceptions.NonexistentEntityException;
import de.swta.freezay.database.controller.exceptions.PreexistingEntityException;
import de.swta.freezay.database.dbEntities.Package;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;
import javax.persistence.EntityNotFoundException;
import de.swta.freezay.database.dbEntities.Category;
import de.swta.freezay.database.dbEntities.ItemPackage;
import java.util.ArrayList;
import java.util.List;
import de.swta.freezay.database.dbEntities.Reservation;
import java.lang.Integer;

/**
 *
 * @author Christian
 */
public class PackageJpaController {

    public PackageJpaController() {
        emf = Persistence.createEntityManagerFactory("FreezayPU");
    }
    private EntityManagerFactory emf = null;

    public EntityManager getEntityManager() {
        return emf.createEntityManager();
    }

    public void create(Package package1) throws PreexistingEntityException, Exception {
        if (package1.getItemPackageCollection() == null) {
            package1.setItemPackageCollection(new ArrayList<ItemPackage>());
        }
        if (package1.getReservationCollection() == null) {
            package1.setReservationCollection(new ArrayList<Reservation>());
        }
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            Category category = package1.getCategory();
            if (category != null) {
                category = em.getReference(category.getClass(), category.getId());
                package1.setCategory(category);
            }
            List<ItemPackage> attachedItemPackageCollection = new ArrayList<ItemPackage>();
            for (ItemPackage itemPackageCollectionItemPackageToAttach : package1.getItemPackageCollection()) {
                itemPackageCollectionItemPackageToAttach = em.getReference(itemPackageCollectionItemPackageToAttach.getClass(), itemPackageCollectionItemPackageToAttach.getItemPackagePK());
                attachedItemPackageCollection.add(itemPackageCollectionItemPackageToAttach);
            }
            package1.setItemPackageCollection(attachedItemPackageCollection);
            List<Reservation> attachedReservationCollection = new ArrayList<Reservation>();
            for (Reservation reservationCollectionReservationToAttach : package1.getReservationCollection()) {
                reservationCollectionReservationToAttach = em.getReference(reservationCollectionReservationToAttach.getClass(), reservationCollectionReservationToAttach.getReservationNr());
                attachedReservationCollection.add(reservationCollectionReservationToAttach);
            }
            package1.setReservationCollection(attachedReservationCollection);
            em.persist(package1);
            if (category != null) {
                category.getPackageCollection().add(package1);
                category = em.merge(category);
            }
            for (ItemPackage itemPackageCollectionItemPackage : package1.getItemPackageCollection()) {
                Package oldPackage1OfItemPackageCollectionItemPackage = itemPackageCollectionItemPackage.getPackage1();
                itemPackageCollectionItemPackage.setPackage1(package1);
                itemPackageCollectionItemPackage = em.merge(itemPackageCollectionItemPackage);
                if (oldPackage1OfItemPackageCollectionItemPackage != null) {
                    oldPackage1OfItemPackageCollectionItemPackage.getItemPackageCollection().remove(itemPackageCollectionItemPackage);
                    oldPackage1OfItemPackageCollectionItemPackage = em.merge(oldPackage1OfItemPackageCollectionItemPackage);
                }
            }
            for (Reservation reservationCollectionReservation : package1.getReservationCollection()) {
                Package oldPackage1OfReservationCollectionReservation = reservationCollectionReservation.getPackage1();
                reservationCollectionReservation.setPackage1(package1);
                reservationCollectionReservation = em.merge(reservationCollectionReservation);
                if (oldPackage1OfReservationCollectionReservation != null) {
                    oldPackage1OfReservationCollectionReservation.getReservationCollection().remove(reservationCollectionReservation);
                    oldPackage1OfReservationCollectionReservation = em.merge(oldPackage1OfReservationCollectionReservation);
                }
            }
            em.getTransaction().commit();
        } catch (Exception ex) {
            if (findPackage(package1.getId()) != null) {
                throw new PreexistingEntityException("Package " + package1 + " already exists.", ex);
            }
            throw ex;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public void edit(Package package1) throws IllegalOrphanException, NonexistentEntityException, Exception {
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            Package persistentPackage = em.find(Package.class, package1.getId());
            Category categoryOld = persistentPackage.getCategory();
            Category categoryNew = package1.getCategory();
            List<ItemPackage> itemPackageCollectionOld = persistentPackage.getItemPackageCollection();
            List<ItemPackage> itemPackageCollectionNew = package1.getItemPackageCollection();
            List<Reservation> reservationCollectionOld = persistentPackage.getReservationCollection();
            List<Reservation> reservationCollectionNew = package1.getReservationCollection();
            List<String> illegalOrphanMessages = null;
            for (ItemPackage itemPackageCollectionOldItemPackage : itemPackageCollectionOld) {
                if (!itemPackageCollectionNew.contains(itemPackageCollectionOldItemPackage)) {
                    if (illegalOrphanMessages == null) {
                        illegalOrphanMessages = new ArrayList<String>();
                    }
                    illegalOrphanMessages.add("You must retain ItemPackage " + itemPackageCollectionOldItemPackage + " since its package1 field is not nullable.");
                }
            }
            if (illegalOrphanMessages != null) {
                throw new IllegalOrphanException(illegalOrphanMessages);
            }
            if (categoryNew != null) {
                categoryNew = em.getReference(categoryNew.getClass(), categoryNew.getId());
                package1.setCategory(categoryNew);
            }
            List<ItemPackage> attachedItemPackageCollectionNew = new ArrayList<ItemPackage>();
            for (ItemPackage itemPackageCollectionNewItemPackageToAttach : itemPackageCollectionNew) {
                itemPackageCollectionNewItemPackageToAttach = em.getReference(itemPackageCollectionNewItemPackageToAttach.getClass(), itemPackageCollectionNewItemPackageToAttach.getItemPackagePK());
                attachedItemPackageCollectionNew.add(itemPackageCollectionNewItemPackageToAttach);
            }
            itemPackageCollectionNew = attachedItemPackageCollectionNew;
            package1.setItemPackageCollection(itemPackageCollectionNew);
            List<Reservation> attachedReservationCollectionNew = new ArrayList<Reservation>();
            for (Reservation reservationCollectionNewReservationToAttach : reservationCollectionNew) {
                reservationCollectionNewReservationToAttach = em.getReference(reservationCollectionNewReservationToAttach.getClass(), reservationCollectionNewReservationToAttach.getReservationNr());
                attachedReservationCollectionNew.add(reservationCollectionNewReservationToAttach);
            }
            reservationCollectionNew = attachedReservationCollectionNew;
            package1.setReservationCollection(reservationCollectionNew);
            package1 = em.merge(package1);
            if (categoryOld != null && !categoryOld.equals(categoryNew)) {
                categoryOld.getPackageCollection().remove(package1);
                categoryOld = em.merge(categoryOld);
            }
            if (categoryNew != null && !categoryNew.equals(categoryOld)) {
                categoryNew.getPackageCollection().add(package1);
                categoryNew = em.merge(categoryNew);
            }
            for (ItemPackage itemPackageCollectionNewItemPackage : itemPackageCollectionNew) {
                if (!itemPackageCollectionOld.contains(itemPackageCollectionNewItemPackage)) {
                    Package oldPackage1OfItemPackageCollectionNewItemPackage = itemPackageCollectionNewItemPackage.getPackage1();
                    itemPackageCollectionNewItemPackage.setPackage1(package1);
                    itemPackageCollectionNewItemPackage = em.merge(itemPackageCollectionNewItemPackage);
                    if (oldPackage1OfItemPackageCollectionNewItemPackage != null && !oldPackage1OfItemPackageCollectionNewItemPackage.equals(package1)) {
                        oldPackage1OfItemPackageCollectionNewItemPackage.getItemPackageCollection().remove(itemPackageCollectionNewItemPackage);
                        oldPackage1OfItemPackageCollectionNewItemPackage = em.merge(oldPackage1OfItemPackageCollectionNewItemPackage);
                    }
                }
            }
            for (Reservation reservationCollectionOldReservation : reservationCollectionOld) {
                if (!reservationCollectionNew.contains(reservationCollectionOldReservation)) {
                    reservationCollectionOldReservation.setPackage1(null);
                    reservationCollectionOldReservation = em.merge(reservationCollectionOldReservation);
                }
            }
            for (Reservation reservationCollectionNewReservation : reservationCollectionNew) {
                if (!reservationCollectionOld.contains(reservationCollectionNewReservation)) {
                    Package oldPackage1OfReservationCollectionNewReservation = reservationCollectionNewReservation.getPackage1();
                    reservationCollectionNewReservation.setPackage1(package1);
                    reservationCollectionNewReservation = em.merge(reservationCollectionNewReservation);
                    if (oldPackage1OfReservationCollectionNewReservation != null && !oldPackage1OfReservationCollectionNewReservation.equals(package1)) {
                        oldPackage1OfReservationCollectionNewReservation.getReservationCollection().remove(reservationCollectionNewReservation);
                        oldPackage1OfReservationCollectionNewReservation = em.merge(oldPackage1OfReservationCollectionNewReservation);
                    }
                }
            }
            em.getTransaction().commit();
        } catch (Exception ex) {
            String msg = ex.getLocalizedMessage();
            if (msg == null || msg.length() == 0) {
                Integer id = package1.getId();
                if (findPackage(id) == null) {
                    throw new NonexistentEntityException("The package with id " + id + " no longer exists.");
                }
            }
            throw ex;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public void destroy(Integer id) throws IllegalOrphanException, NonexistentEntityException {
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            Package package1;
            try {
                package1 = em.getReference(Package.class, id);
                package1.getId();
            } catch (EntityNotFoundException enfe) {
                throw new NonexistentEntityException("The package1 with id " + id + " no longer exists.", enfe);
            }
            List<String> illegalOrphanMessages = null;
            List<ItemPackage> itemPackageCollectionOrphanCheck = package1.getItemPackageCollection();

            // #TODO: JK - hier müssen beim löschen von einem Paket die entsprechenden ItemPakages erst gelöscht werden
            for (ItemPackage itemPackageCollectionOrphanCheckItemPackage : itemPackageCollectionOrphanCheck) {
                if (illegalOrphanMessages == null) {
                    illegalOrphanMessages = new ArrayList<String>();
                }
                illegalOrphanMessages.add("This Package (" + package1 + ") cannot be destroyed since the ItemPackage " + itemPackageCollectionOrphanCheckItemPackage + " in its itemPackageCollection field has a non-nullable package1 field.");
            }
            if (illegalOrphanMessages != null) {
                throw new IllegalOrphanException(illegalOrphanMessages);
            }
            Category category = package1.getCategory();
            if (category != null) {
                category.getPackageCollection().remove(package1);
                category = em.merge(category);
            }
            List<Reservation> reservationCollection = package1.getReservationCollection();
            for (Reservation reservationCollectionReservation : reservationCollection) {
                reservationCollectionReservation.setPackage1(null);
                reservationCollectionReservation = em.merge(reservationCollectionReservation);
            }
            em.remove(package1);
            em.getTransaction().commit();
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public boolean isUsed(Integer id) {
        boolean isUsed = false;

        Package packageToTest = this.findPackage(id);

        if (packageToTest != null) {
            isUsed = (/*packageToTest.getItemPackageCollection().size() != 0
                    ||*/ packageToTest.getReservationCollection().size() != 0);
        }

        return isUsed;
    }

    public List<Package> findPackageEntities() {
        return findPackageEntities(true, -1, -1);
    }

    public List<Package> findPackageEntities(int maxResults, int firstResult) {
        return findPackageEntities(false, maxResults, firstResult);
    }

    private List<Package> findPackageEntities(boolean all, int maxResults, int firstResult) {
        EntityManager em = getEntityManager();
        try {
            Query q = em.createQuery("select object(o) from Package as o");
            if (!all) {
                q.setMaxResults(maxResults);
                q.setFirstResult(firstResult);
            }
            return q.getResultList();
        } finally {
            em.close();
        }
    }

    public List<Package> findPackageEntitiesAdmin(int maxResults, int firstResult,
            String sortBy, boolean ascending) {

        EntityManager em = getEntityManager();
        try {
            Query q = em.createQuery("select object(o) from Package as o order "
                    + "by o." + sortBy + " " + (ascending ? "ASC" : "DESC"));

            q.setMaxResults(maxResults);
            q.setFirstResult(firstResult);

            return q.getResultList();
        } finally {
            em.close();
        }
    }

    public List<Package> findPackageEntitiesUser(int maxResults, int firstResult,
            String sortBy, boolean ascending) {

        EntityManager em = getEntityManager();
        try {
            String query =
                      "SELECT * "
                    + "FROM Package AS o "
                    + "WHERE (o.count > (SELECT SUM(rb.packagecount) "
                    + "                  FROM Reservation AS rb "
                    + "                  WHERE o.id = rb.package)  "
                    + "       OR NOT EXISTS (SELECT * "
                    + "                      FROM Reservation AS ra "
                    + "                      WHERE o.id = ra.package)) "
                    + "AND o.count > 0 "
                    + "AND o.validity > CURRENT_TIMESTAMP "
                    + "ORDER BY o." + sortBy + " "
                    + (ascending ? "ASC" : "DESC");

            Query q = em.createNativeQuery(query, Package.class);
            q.setMaxResults(maxResults);
            q.setFirstResult(firstResult);
           
            return q.getResultList();        
        } finally {
            em.close();
        }

    }


    public Package findPackage(Integer id) {
        EntityManager em = getEntityManager();
        try {
            return em.find(Package.class, id);
        } finally {
            em.close();
        }
    }

    public int getPackageCountUser() {
        EntityManager em = getEntityManager();
        try {
            String query =
                      "SELECT * "
                    + "FROM Package AS o "
                    + "WHERE (o.count > (SELECT SUM(rb.packagecount) "
                    + "                  FROM Reservation AS rb "
                    + "                  WHERE o.id = rb.package)  "
                    + "       OR NOT EXISTS (SELECT * "
                    + "                      FROM Reservation AS ra "
                    + "                      WHERE o.id = ra.package)) "
                    + "AND o.count > 0 "
                    + "AND o.validity > CURRENT_TIMESTAMP ";

            Query q = em.createNativeQuery(query, Package.class);

            return q.getResultList().size(); 
        } finally {
            em.close();
        }
    }

    public int getPackageCountAdmin() {
        EntityManager em = getEntityManager();
        try {
            return ((Long) em.createQuery("select count(o) from Package as o").getSingleResult()).intValue();
        } finally {
            em.close();
        }
    }

}
